/*
 * i2c_support.c
 *
 *  Created on: Feb 28, 2013
 *      Author: Kurt Hardin
 */

#include "i2c_support.h"
#include "support_common.h"

/*
 * I2C port init.
 * Configure the I2C port so we can talk to the HMC5883	magnetometer.
 */
void mcf52233_i2c_init(void)
{
	uint8 temp;
	
	MCF_GPIO_PASPAR = 0x05;
	
    MCF_I2C_I2FDR = 0x38;							// divide CPU clock by 640 to 100KHz ?
    MCF_I2C_I2CR = MCF_I2C_I2CR_IEN;				// Turn on the I2C port

    // if bit busy set, send a stop condition to slave module.
    if( MCF_I2C_I2SR & MCF_I2C_I2SR_IBB)
    {
        MCF_I2C_I2CR = 0;							/* clear control register */
        MCF_I2C_I2CR = MCF_I2C_I2CR_IEN |			/* enable module */
                       MCF_I2C_I2CR_MSTA;       	/* send a START condition */
        temp = MCF_I2C_I2DR;                    	/* dummy read */
        MCF_I2C_I2SR = 0;							/* clear status register */
        MCF_I2C_I2CR = 0;							/* clear control register */
        MCF_I2C_I2CR = 0 | MCF_I2C_I2CR_IEN;		/* enable the module again */
    }   
}

// Reads a single byte from the specified slave I2C bus.
uint8 mcf52233_i2c_read(uint8 slave_addr, uint8 reg_addr) 
{   
	uint8 data;
	mcf52233_i2c_read(slave_addr, reg_addr, &data, 1);
	return data;
}

// Reads multiple consecutive bytes from the specified slave on the I2C bus.
void mcf52233_i2c_read(uint8 slave_addr, uint8 reg_addr, uint8 *data, uint8 bytes)
{
	if (bytes == 0) {
		return;
	}
	
	int i;
	
	// Wait if the bus is busy or a transfer is in progress
	while (~MCF_I2C_I2SR & MCF_I2C_I2SR_ICF  ||                	// Wait here while either xfer is not done..
		  MCF_I2C_I2SR & MCF_I2C_I2SR_IBB) {};                	// or the bus is busy

	MCF_I2C_I2SR &= ~MCF_I2C_I2SR_IIF;                        	// clear the interrupt flag if on
   
	MCF_I2C_I2CR &= ~MCF_I2C_I2CR_TXAK;                        	// enable the ACK
	MCF_I2C_I2CR |= MCF_I2C_I2CR_MTX;                        	// Set to transmit Mode
	MCF_I2C_I2CR |= MCF_I2C_I2CR_MSTA;                        	// Generate the START condition
	
	MCF_I2C_I2DR = ((slave_addr << 1) & 0xFE);					// Send the write control byte

	while(~MCF_I2C_I2SR & MCF_I2C_I2SR_IIF){};               	// then wait for the control byte done
	MCF_I2C_I2SR &= ~MCF_I2C_I2SR_IIF;                       	// clear the flag

	MCF_I2C_I2DR = reg_addr;									// Send the register address
   
	while(~MCF_I2C_I2SR & MCF_I2C_I2SR_IIF){};              	// then wait for address to go out
	MCF_I2C_I2SR &= ~MCF_I2C_I2SR_IIF;                      	// clear the flag
   
	MCF_I2C_I2CR |= MCF_I2C_I2CR_RSTA;                       	// Generate a REPEAT START condition
	
	MCF_I2C_I2DR = ((slave_addr << 1) | 0x01);		 			// Send the read control byte

	while(~MCF_I2C_I2SR & MCF_I2C_I2SR_IIF){};                	// then wait for control byte to go out
	MCF_I2C_I2SR &= ~MCF_I2C_I2SR_IIF;                        	// clear the flag
	
	MCF_I2C_I2CR &= ~MCF_I2C_I2CR_MTX;                  	// Setup for the last xfer
	
	if (bytes == 1) {
		MCF_I2C_I2CR |= MCF_I2C_I2CR_TXAK;                  	// Setup for no ack.... 
	} 
	else 
	{
		MCF_I2C_I2CR &= ~MCF_I2C_I2CR_TXAK;						// Setup to send ack
	}
	
	data[0] = MCF_I2C_I2DR;                                		// Dummy xfer to trigger the read
	
	for (i = 0; i < bytes; i++) {
		while(~MCF_I2C_I2SR & MCF_I2C_I2SR_IIF){}              	// wait for read data
		MCF_I2C_I2SR &= ~MCF_I2C_I2SR_IIF;                 		// clear the flag
		
		if (i == bytes - 2) {
			MCF_I2C_I2CR &= ~MCF_I2C_I2CR_MTX;                 	// setup for the last xfer
			MCF_I2C_I2CR |= MCF_I2C_I2CR_TXAK;                 	// Setup for no ack.... 
		}
		
		if (i == bytes - 1) {
			MCF_I2C_I2CR &= ~MCF_I2C_I2CR_MSTA;                 // Send the stop condition
		}
		
		data[i] = (MCF_I2C_I2DR & 0xFF);						// Read the byte
	}
}

// Writes a single byte to the specified slave on the I2C bus.
void mcf52233_i2c_write(uint8 slave_addr, uint8 reg_addr, uint8 data)
{
	mcf52233_i2c_write(slave_addr, reg_addr, &data, 1);
}

// Writes multiple consecutive bytes to the specified slave on the I2C bus.
void mcf52233_i2c_write(uint8 slave_addr, uint8 reg_addr, uint8 * data, uint8 bytes)
{
	if (bytes == 0) {
		return;
	}
	
	int i;
	
	while (~MCF_I2C_I2SR & MCF_I2C_I2SR_ICF  ||                	// Wait here while either xfer is not done..
			  MCF_I2C_I2SR & MCF_I2C_I2SR_IBB) {};
	
	MCF_I2C_I2CR &= ~MCF_I2C_I2CR_TXAK;                        	// Enable the ACK
	MCF_I2C_I2CR |= MCF_I2C_I2CR_MTX;                        	// Set to transmit mode
	MCF_I2C_I2CR |= MCF_I2C_I2CR_MSTA;                        	// Generate the START condition
	MCF_I2C_I2DR = (slave_addr << 1) & 0xFE;					// Send the control byte

	while(~MCF_I2C_I2SR & MCF_I2C_I2SR_IIF){};                	// Wait for the control byte to be sent
	MCF_I2C_I2SR &= ~MCF_I2C_I2SR_IIF;                        	// Clear the flag

	MCF_I2C_I2DR = reg_addr & 0xFF;                            	// Send the register address
   
	while(~MCF_I2C_I2SR & MCF_I2C_I2SR_IIF){};                	// Wait for address to go out
	MCF_I2C_I2SR &= ~MCF_I2C_I2SR_IIF;                        	// Clear the flag

	for (i = 0; i < bytes; i++) {
		MCF_I2C_I2DR = data[i];                                    	// Write the data
	   
		while(~MCF_I2C_I2SR & MCF_I2C_I2SR_IIF){};                	// Wait for data to go out
		MCF_I2C_I2SR &= ~MCF_I2C_I2SR_IIF;                        	// clear the flag
	}
	
	MCF_I2C_I2CR &= ~MCF_I2C_I2CR_MSTA;                        	// Send the stop condition
}
